package com.mc.fastkit.widget

import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Rect
import android.graphics.drawable.ColorDrawable
import android.graphics.drawable.Drawable
import android.view.View
import androidx.annotation.ColorInt
import androidx.core.view.forEach
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.ItemDecoration
import androidx.recyclerview.widget.StaggeredGridLayoutManager
import com.mc.fastkit.ext.dp2pxi

/**
 * [RecyclerView]分割线，不支持[StaggeredGridLayoutManager]
 * @author: MasterChan
 * @date: 2023-12-11 17:54
 */
open class XDivider : ItemDecoration() {
    /**
     * 分割线间距
     */
    private var spacing = 0

    /**
     * 分割线
     */
    private var drawable: Drawable? = null

    /**
     * 分割线绘制方向
     */
    private var orientation: Int = RecyclerView.HORIZONTAL

    /**
     * 是否绘制第一个的顶部分割线
     */
    private var isDrawFirst = false

    /**
     * 是否绘制最后一个的底部分割线
     */
    private var isDrawLast = false

    /**
     * 分割线是否在Item的margin内
     */
    private var includeMargin = false

    /**
     * 同时有垂直、水平分割线时，分割线间断，是否将水平分割线对接
     */
    private var dockingHorizontal = false

    /**
     *  同时有垂直、水平分割线时，分割线间断，是否将垂直分割线对接
     */
    private var dockingVertical = false

    /**
     * 分割线左边距
     */
    private var startPadding = 0

    /**
     * 分割线顶边距
     */
    private var topPadding = 0

    /**
     * 分割线右边距
     */
    private var endPadding = 0

    /**
     * 分割线下边距
     */
    private var bottomPadding = 0

    override fun onDraw(canvas: Canvas, parent: RecyclerView, state: RecyclerView.State) {
        parent.forEach { child ->
            val params = child.layoutParams as RecyclerView.LayoutParams
            val startMargin = if (includeMargin) 0 else params.marginStart
            val topMargin = if (includeMargin) 0 else params.topMargin
            val endMargin = if (includeMargin) 0 else params.marginEnd
            val bottomMargin = if (includeMargin) 0 else params.bottomMargin
            val left: Int
            val top: Int
            val right: Int
            val bottom: Int
            if (orientation == RecyclerView.HORIZONTAL) {
                val dockingOffset = if (dockingHorizontal) spacing else 0
                val leftOffset = if (isFirstColumn(child, parent)) dockingOffset else 0
                left = child.left - startMargin + startPadding - leftOffset
                right = child.right + endMargin - endPadding + dockingOffset
                top = child.bottom + bottomMargin
                bottom = if (!isDrawLast && isLastRow(child, parent)) top else top + spacing
                if (isDrawFirst && isFirstRow(child, parent)) {
                    val firstBottom = child.top - topMargin
                    val firstTop = firstBottom - spacing
                    drawable?.setBounds(left, firstTop, right, firstBottom)
                    drawable?.draw(canvas)
                }
            } else {
                val dockingOffset = if (dockingVertical) spacing else 0
                val topOffset = if (isFirstRow(child, parent)) dockingOffset else 0
                top = child.top - topMargin + topPadding - topOffset
                bottom = child.bottom + bottomMargin - bottomPadding + dockingOffset
                left = child.right + endMargin
                right = if (!isDrawLast && isLastColumn(child, parent)) left else left + spacing
                if (isFirstColumn(child, parent) && isDrawFirst) {
                    val firstRight = child.left - startMargin
                    val firstLeft = firstRight - spacing
                    drawable?.setBounds(firstLeft, top, firstRight, bottom)
                    drawable?.draw(canvas)
                }
            }
            drawable?.setBounds(left, top, right, bottom)
            drawable?.draw(canvas)
        }
    }

    override fun getItemOffsets(
        outRect: Rect,
        view: View,
        parent: RecyclerView,
        state: RecyclerView.State
    ) {
        when (parent.layoutManager) {
            is GridLayoutManager -> getItemOffsetsWhenGrid(outRect, view, parent, state)
            is LinearLayoutManager -> getItemOffsetsWhenLinear(outRect, view, parent, state)
            else -> {}
        }
    }

    /**
     * 当[RecyclerView.LayoutManager]为[LinearLayoutManager]时的处理
     * @param outRect Rect
     * @param view View
     * @param parent RecyclerView
     * @param state: RecyclerView.State
     */
    protected open fun getItemOffsetsWhenLinear(
        outRect: Rect,
        view: View,
        parent: RecyclerView,
        state: RecyclerView.State
    ) {
        if (parent.adapter == null || parent.layoutManager == null) {
            super.getItemOffsets(outRect, view, parent, state)
            return
        }
        val top: Int
        val left: Int
        val right: Int
        val bottom: Int
        if (orientation == RecyclerView.VERTICAL) {
            top = 0
            bottom = 0
            left = if (isDrawFirst && isFirstColumn(view, parent)) spacing else 0
            right = if (!isDrawLast && isLastColumn(view, parent)) 0 else spacing
        } else {
            left = 0
            right = 0
            top = if (isDrawFirst && isFirstRow(view, parent)) spacing else 0
            bottom = if (!isDrawLast && isLastRow(view, parent)) 0 else spacing
        }
        outRect.set(left, top, right, bottom)
    }

    /**
     * 当[RecyclerView.LayoutManager]为[GridLayoutManager]时的处理
     * @param outRect Rect
     * @param view View
     * @param parent RecyclerView
     * @param state: RecyclerView.State
     */
    protected open fun getItemOffsetsWhenGrid(
        outRect: Rect,
        view: View,
        parent: RecyclerView,
        state: RecyclerView.State
    ) {
        if (parent.adapter == null || parent.layoutManager == null) {
            super.getItemOffsets(outRect, view, parent, state)
            return
        }
        if ((parent.layoutManager as GridLayoutManager).orientation == RecyclerView.VERTICAL) {
            getItemOffsetsWhenGridV(outRect, view, parent, state)
        } else {
            getItemOffsetsWhenGridH(outRect, view, parent, state)
        }
    }

    protected open fun getItemOffsetsWhenGridV(
        outRect: Rect,
        view: View,
        parent: RecyclerView,
        state: RecyclerView.State
    ) {
        val left: Int
        val top: Int
        val right: Int
        val bottom: Int
        if (orientation == RecyclerView.HORIZONTAL) {
            left = 0
            right = 0
            top = if (isDrawFirst && isFirstRow(view, parent)) spacing else 0
            bottom = if (!isDrawLast && isLastRow(view, parent)) 0 else spacing
        } else {
            val spanIndex = (view.layoutParams as GridLayoutManager.LayoutParams).spanIndex
            val spanCount = (parent.layoutManager as GridLayoutManager).spanCount
            top = 0
            bottom = 0
            when {
                isDrawFirst && isDrawLast -> {
                    left = spacing - spanIndex * spacing / spanCount
                    right = (spanIndex + 1) * spacing / spanCount
                }

                isDrawFirst && !isDrawLast -> {
                    left = spacing
                    right = 0
                }

                !isDrawFirst && isDrawLast -> {
                    left = 0
                    right = spacing
                }

                else -> {
                    left = spanIndex * spacing / spanCount
                    right = spacing - (spanIndex + 1) * spacing / spanCount
                }
            }
        }
        outRect.set(left, top, right, bottom)
    }

    protected open fun getItemOffsetsWhenGridH(
        outRect: Rect,
        view: View,
        parent: RecyclerView,
        state: RecyclerView.State
    ) {
        val position = parent.getChildAdapterPosition(view)
        val layoutManager = parent.layoutManager as GridLayoutManager
        val spanCount = layoutManager.spanCount

        val left: Int
        val top: Int
        val right: Int
        val bottom: Int
        if (orientation == RecyclerView.HORIZONTAL) {
            left = 0
            right = 0
            val spanIndex = layoutManager.spanSizeLookup.getSpanIndex(position, spanCount)
            when {
                isDrawFirst && isDrawLast -> {
                    top = spacing - spanIndex * spacing / spanCount
                    bottom = (spanIndex + 1) * spacing / spanCount
                }

                isDrawFirst && !isDrawLast -> {
                    top = spacing
                    bottom = 0
                }

                !isDrawFirst && isDrawLast -> {
                    top = 0
                    bottom = spacing
                }

                else -> {
                    top = spanIndex * spacing / spanCount
                    bottom = spacing - (spanIndex + 1) * spacing / spanCount
                }
            }
        } else {
            top = 0
            bottom = 0
            left = if (isDrawFirst && isFirstColumn(view, parent)) spacing else 0
            right = if (!isDrawLast && isLastColumn(view, parent)) 0 else spacing
        }
        outRect.set(left, top, right, bottom)
    }

    protected open fun isFirstRow(child: View, parent: RecyclerView): Boolean {
        return when (val layoutManager = parent.layoutManager) {
            is GridLayoutManager -> {
                val itemPosition = parent.getChildAdapterPosition(child)
                val spanCount = layoutManager.spanCount
                if (layoutManager.orientation == RecyclerView.VERTICAL) {
                    itemPosition < spanCount
                } else {
                    itemPosition % spanCount == 0
                }
            }

            is LinearLayoutManager -> {
                if (layoutManager.orientation == RecyclerView.VERTICAL) {
                    parent.getChildAdapterPosition(child) == 0
                } else {
                    true
                }
            }

            else -> false
        }
    }

    protected open fun isLastRow(child: View, parent: RecyclerView): Boolean {
        val childCount = parent.adapter!!.itemCount
        val itemPosition = parent.getChildAdapterPosition(child)
        return when (val layoutManager = parent.layoutManager) {
            is GridLayoutManager -> {
                val spanCount = layoutManager.spanCount
                if (layoutManager.orientation == GridLayoutManager.VERTICAL) {
                    val maxIndex = if (childCount % spanCount == 0) {
                        ((childCount / spanCount) - 1) * spanCount
                    } else {
                        (childCount / spanCount) * spanCount
                    }
                    itemPosition >= maxIndex
                } else {
                    (itemPosition + 1) % spanCount == 0
                }
            }

            is LinearLayoutManager -> {
                if (layoutManager.orientation == RecyclerView.VERTICAL) {
                    itemPosition == childCount - 1
                } else {
                    true
                }
            }

            else -> false
        }
    }

    protected open fun isFirstColumn(child: View, parent: RecyclerView): Boolean {
        return when (val layoutManager = parent.layoutManager) {
            is GridLayoutManager -> {
                val itemPosition = parent.getChildAdapterPosition(child)
                val spanCount = layoutManager.spanCount
                if (layoutManager.orientation == RecyclerView.VERTICAL) {
                    itemPosition % spanCount == 0
                } else {
                    itemPosition < spanCount
                }
            }

            is LinearLayoutManager -> {
                if (layoutManager.orientation == RecyclerView.VERTICAL) {
                    true
                } else {
                    parent.getChildAdapterPosition(child) == 0
                }
            }

            else -> false
        }
    }

    protected open fun isLastColumn(child: View, parent: RecyclerView): Boolean {
        val childCount = parent.adapter!!.itemCount
        val itemPosition = parent.getChildAdapterPosition(child)
        return when (val layoutManager = parent.layoutManager) {
            is GridLayoutManager -> {
                val spanCount = layoutManager.spanCount
                if (layoutManager.orientation == StaggeredGridLayoutManager.VERTICAL) {
                    (itemPosition + 1) % spanCount == 0
                } else {
                    val maxIndex = if (childCount % spanCount == 0) {
                        ((childCount / spanCount) - 1) * spanCount
                    } else {
                        (childCount / spanCount) * spanCount
                    }
                    itemPosition >= maxIndex
                }
            }

            is LinearLayoutManager -> {
                if (layoutManager.orientation == RecyclerView.VERTICAL) {
                    true
                } else {
                    itemPosition == childCount - 1
                }
            }

            else -> false
        }
    }

    fun setOrientation(orientation: Int) = apply {
        this.orientation = orientation
    }

    fun setSpacing(spacing: Float) = apply {
        this.spacing = dp2pxi(spacing)
    }

    fun setSpacing(spacing: Int) = apply {
        this.spacing = dp2pxi(spacing)
    }

    fun setDividerColor(@ColorInt color: Int) = apply {
        this.drawable = ColorDrawable(color)
    }

    fun setDividerColor(color: String) = apply {
        this.drawable = ColorDrawable(Color.parseColor(color))
    }

    fun setDividerDrawable(drawable: Drawable) = apply {
        this.drawable = drawable
    }

    fun setDrawEdge(drawEdge: Boolean) = apply {
        this.isDrawFirst = drawEdge
        this.isDrawLast = drawEdge
    }

    fun setDrawFirst(isDrawFirst: Boolean) = apply {
        this.isDrawFirst = isDrawFirst
    }

    fun setDrawLast(isDrawLast: Boolean) = apply {
        this.isDrawLast = isDrawLast
    }

    fun setIncludeMargin(includeMargin: Boolean) = apply {
        this.includeMargin = includeMargin
    }

    fun setDockingHorizontal(dockingHorizontal: Boolean) = apply {
        this.dockingHorizontal = dockingHorizontal
    }

    fun setDockingVertical(dockingVertical: Boolean) = apply {
        this.dockingVertical = dockingVertical
    }

    fun setStartPadding(startPadding: Int) = apply {
        this.startPadding = startPadding
    }

    fun setTopPadding(topPadding: Int) = apply {
        this.topPadding = topPadding
    }

    fun setEndPadding(endPadding: Int) = apply {
        this.endPadding = endPadding
    }

    fun setBottomPadding(bottomPadding: Int) = apply {
        this.bottomPadding = bottomPadding
    }

    fun into(recyclerView: RecyclerView) {
        recyclerView.addItemDecoration(this)
    }
}